# boot/head.S

.text
.globl gdt, idt, pg_dir, tmp_floppy_area, start_32, floppy_track_buffer
pg_dir:
start_32:
    cld 
	movl $0x10, %eax 
	mov %ax, %ds 
	mov %ax, %es 
	mov %ax, %fs 
	mov %ax, %gs 
	lss stack_start, %esp 	# stack_start at sched.c 
	call setup_idt 
	call setup_gdt
	movl $0x10, %eax 
	mov %ax, %ds 
	mov %ax, %es 
	mov %ax, %fs 
	mov %ax, %gs
	lss stack_start, %esp 
	
	# check A20
	xorl %eax, %eax 
1: 	incl %eax 
	movl %eax, 0x000000
	cmpl %eax, 0x100000		# address: 1M
	je 1b

    # check 486 or 386
    movl %esp,%edi		# save stack pointer
	andl $0xfffffffc,%esp	# align stack to avoid AC fault
	pushfl			# push EFLAGS
	popl %eax		# get EFLAGS
	movl %eax,%ecx		# save original EFLAGS
	xorl $0x40000,%eax	# flip AC bit in EFLAGS
	pushl %eax		# copy to EFLAGS
	popfl			# set EFLAGS
	pushfl			# get new EFLAGS
	popl %eax		# put it in eax
	xorl %ecx,%eax		# check if AC bit is changed. zero is 486.
	jz 1f			# 486
	pushl %ecx		# restore original EFLAGS
	popfl
	movl %edi,%esp		# restore esp
	movl %cr0,%eax		# 386
	andl $0x80000011,%eax	# Save PG,PE,ET
	orl $2,%eax		# set MP
	jmp 2f	
/*
 * NOTE! 486 should set bit 16, to check for write-protect in supervisor
 * mode. Then it would be unnecessary with the "verify_area()"-calls.
 * 486 users probably want to set the NE (#5) bit also, so as to use
 * int 16 for math errors.
 */
1:	pushl %ecx		# restore original EFLAGS
	popfl
	movl %edi,%esp		# restore esp
	movl %cr0,%eax		# 486
	andl $0x80000011,%eax	# Save PG,PE,ET
	orl $0x10022,%eax	# set NE and MP
2:	movl %eax,%cr0

	// # check math chip
	// movl %cr0, %eax 
	// andl $0x80000011, %eax 	# PG,ET,PE
	// orl $2, %eax
	// movl %eax, %cr0
	
    call check_x87
	jmp after_page_tables 

check_x87:
	fninit
	fstsw %ax 
	cmpb $0, %al 
	je 1f 
	movl %cr0, %eax 
	xorl $6, %eax 
	movl %eax, %cr0 
	ret 
.align 2
1:	.byte 0xdb, 0xe4
	ret 

setup_gdt:
	lgdt gdt_descr
	ret

setup_idt:
	lea ignore_int, %edx 
	movl $0x00080000, %eax 
	movw %dx, %ax 
	movw $0x8e00, %dx 
	lea idt, %edi 
	mov $256, %ecx 
rp_sidt:
	movl %eax, (%edi)
	movl %edx, 4(%edi)
	addl $8, %edi 
	dec %ecx 
	jne rp_sidt
	lidt idt_descr
	ret

	.org 0x1000
pg0:
	.org 0x2000
pg1:
	.org 0x3000
pg2:
	.org 0x4000
pg3:
	.org 0x5000
tmp_floppy_area:
	.fill 1024, 1, 0
floppy_track_buffer:
    .fill 512*2*18, 1, 0

after_page_tables:
	call setup_paging
	pushl $0		# These are the parameters to main :-)
	pushl $0
	pushl $0
	cld			# gcc2 wants the direction flag cleared at all times
	call start_kernel
L6:
	jmp L6	

int_msg:
	.asciz "Unknown interrupt\n\t"
	
	.align 2
ignore_int:
	pushl %eax 
	pushl %ecx 
	pushl %edx 
	push %ds 
	push %es 
	push %fs 
	movl $0x10, %eax 
	mov %ax, %ds 
	mov %ax, %es 
	mov %ax, %fs 
	pushl $int_msg
	call printk
	popl %eax 
	pop %fs 
	pop %es 
	pop %ds 
	popl %edx 
	popl %ecx 
	popl %eax 
	iret 

	.align 2
setup_paging:
	movl $1024*5, %ecx 
	xorl %eax, %eax 
	xorl %edi, %edi 
	cld 
	rep 
	stosl 

	movl $pg0 + 7, pg_dir 
	movl $pg1 + 7, pg_dir + 4
	movl $pg2 + 7, pg_dir + 8
	movl $pg3 + 7, pg_dir + 12 

	movl $pg3 + 4092, %edi 
	movl $0xfff007, %eax 

	std 
1:	stosl 
	subl $0x1000, %eax 
	jge 1b
	cld 

	# base_addr => cr3
	xorl %eax, %eax 
	movl %eax, %cr3

	# 启用分页
	movl %cr0, %eax 
	orl $0x80000000, %eax 
	movl %eax, %cr0

	ret

	.align 2
	.word 0
idt_descr:
	.word 256*8-1
	.long idt 

	.align 2
	.word 0
gdt_descr:
	.word 256*8-1
	.long gdt 

	.align 8
idt:
	.fill 256,8,0

gdt:
	.quad 0x0000000000000000
	.quad 0x00c09a0000000fff
	.quad 0x00c0920000000fff
	.quad 0x0000000000000000
	.fill 252,8,0